home *** CD-ROM | disk | FTP | other *** search
- #!/bin/sh
-
- STATEDIR=/var/lib/initramfs-tools
- BOOTDIR=/boot
- CONF=/etc/initramfs-tools/update-initramfs.conf
- USETRIGGERS=true
- mode=""
- version=""
- update_initramfs=yes
- backup_initramfs=no
-
- set -e
-
- [ -r ${CONF} ] && . ${CONF}
-
- case "$DPKG_MAINTSCRIPT_PACKAGE" in
- linux-image-*)
- if [ -z "$INITRAMFS_TOOLS_KERNEL_HOOK" ]; then
- # kernel maintainer script called us directly; ignore
- # it and let the hook script handle it instead
- echo "update-initramfs: deferring update (hook will be called later)"
- exit 0
- fi
- ;;
- ?*)
- if $USETRIGGERS \
- && [ $# = 1 ] \
- && [ x"$1" = x-u ] \
- && dpkg-trigger --check-supported 2>/dev/null
- then
- if dpkg-trigger --no-await update-initramfs; then
- echo "update-initramfs: deferring update (trigger activated)"
- exit 0
- fi
- fi
- ;;
- esac
-
- usage()
- {
- if [ -n "${1:-}" ]; then
- printf "${*}\n\n" >&2
- fi
- cat >&2 << EOF
- Usage: ${0} [OPTION]...
-
- Options:
- -k [version] Specify kernel version or 'all'
- -c Create a new initramfs
- -u Update an existing initramfs
- -d Remove an existing initramfs
- -t Take over a custom initramfs with this one
- -b Set alternate boot directory
- -v Be verbose
- -h This message
-
- EOF
- exit 1
- }
-
- # chroot check
- chrooted()
- {
- # borrowed from udev's postinst
- if [ "$(stat -c %d/%i /)" = "$(stat -Lc %d/%i /proc/1/root 2>/dev/null)" ]; then
- # the devicenumber/inode pair of / is the same as that of
- # /sbin/init's root, so we're *not* in a chroot and hence
- # return false.
- return 1
- fi
- return 0
- }
-
- mild_panic()
- {
- if [ -n "${1:-}" ]; then
- printf "${*}\n" >&2
- fi
- exit 0
- }
-
- panic()
- {
- if [ -n "${1:-}" ]; then
- printf "${*}\n" >&2
- fi
- exit 1
- }
-
- verbose()
- {
- if [ "${verbose}" = 1 ]; then
- printf "${*}\n"
- fi
- }
-
- version_exists()
- {
- [ -e "${STATEDIR}/${1}" ] && [ -e "${initramfs}" ]
- return $?
- }
-
- set_initramfs()
- {
- initramfs="${BOOTDIR}/initrd.img-${version}"
- }
-
-
- # backup initramfs while running
- backup_initramfs()
- {
- [ ! -r "${initramfs}" ] && return 0
- initramfs_bak="${initramfs}.dpkg-bak"
- [ -r "${initramfs_bak}" ] && rm -f "${initramfs_bak}"
- ln -f "${initramfs}" "${initramfs_bak}" \
- || cp -a "${initramfs}" "${initramfs_bak}"
- verbose "Keeping ${initramfs_bak}"
- }
-
- # keep booted initramfs
- backup_booted_initramfs()
- {
- initramfs_bak="${initramfs}.dpkg-bak"
-
- # first time run thus no backup
- [ ! -r "${initramfs_bak}" ] && return 0
-
- # chroot with no /proc
- [ ! -r /proc/uptime ] && rm -f "${initramfs_bak}" && return 0
-
- # no kept backup wanted
- [ "${backup_initramfs}" = "no" ] && rm -f "${initramfs_bak}" && return 0
-
- # no backup yet
- if [ ! -r "${initramfs}.bak" ]; then
- mv -f ${initramfs_bak} "${initramfs}.bak"
- verbose "Backup ${initramfs}.bak"
- return 0
- fi
-
- # keep booted initramfs
- boot_initramfs=
- uptime_days=$(awk '{printf "%d", $1 / 3600 / 24}' /proc/uptime)
- if [ -n "$uptime_days" ]; then
- boot_initramfs=$(find "${initramfs}.bak" -mtime +${uptime_days})
- fi
- if [ -n "${boot_initramfs}" ]; then
- mv -f "${initramfs_bak}" "${initramfs}.bak"
- verbose "Backup ${initramfs}.bak"
- return 0
- fi
- verbose "Removing current backup ${initramfs_bak}"
- rm -f ${initramfs_bak}
- }
-
- # nuke generated copy
- remove_initramfs_bak()
- {
- [ -z "${initramfs_bak:-}" ] && return 0
- rm -f "${initramfs_bak}"
- verbose "Removing ${initramfs_bak}"
- }
-
-
- generate_initramfs()
- {
- echo "update-initramfs: Generating ${initramfs}"
- OPTS="-o"
- if [ "${verbose}" = 1 ]; then
- OPTS="-v ${OPTS}"
- fi
- if mkinitramfs ${OPTS} "${initramfs}.new" "${version}"; then
- mv -f "${initramfs}.new" "${initramfs}"
- set_sha1
- else
- mkinitramfs_return="$?"
- remove_initramfs_bak
- rm -f "${initramfs}.new"
- echo "update-initramfs: failed for ${initramfs} with $mkinitramfs_return." >&2
- exit $mkinitramfs_return
- fi
- }
-
- # Invoke bootloader
- run_bootloader()
- {
- # invoke policy conformant bootloader hooks
- if [ -d /etc/initramfs/post-update.d/ ]; then
- run-parts --arg=${version} --arg=${initramfs} \
- /etc/initramfs/post-update.d/
- return 0
- fi
- }
-
- compare_sha1()
- {
- sha1sum "${initramfs}" | diff "${STATEDIR}/${version}" - >/dev/null 2>&1
- return $?
- }
-
- # Note that this must overwrite so that updates work.
- set_sha1()
- {
- sha1sum "${initramfs}" > "${STATEDIR}/${version}"
- }
-
- delete_sha1()
- {
- rm -f "${STATEDIR}/${version}"
- }
-
- # ro /boot is not modified
- ro_boot_check()
- {
- # check irrelevant inside of a chroot
- if [ ! -r /proc/mounts ] || chrooted; then
- return 0
- fi
-
- boot_opts=$(awk '/boot/{if ((match($4, /^ro/) || match($4, /,ro/)) \
- && $2 == "/boot") print "ro"}' /proc/mounts)
- if [ -n "${boot_opts}" ]; then
- echo "WARNING: /boot is ro mounted."
- echo "update-initramfs: Not updating ${initramfs}"
- exit 0
- fi
- }
-
- get_sorted_versions()
- {
- version_list=""
-
- for gsv_x in "${STATEDIR}"/*; do
- gsv_x="$(basename "${gsv_x}")"
- if [ "${gsv_x}" = '*' ]; then
- return 0
- fi
- worklist=""
- for gsv_i in $version_list; do
- if dpkg --compare-versions "${gsv_x}" '>' "${gsv_i}" 2>/dev/null; then
- worklist="${worklist} ${gsv_x} ${gsv_i}"
- gsv_x=""
- else
- worklist="${worklist} ${gsv_i}"
- fi
- done
- if [ "${gsv_x}" != "" ]; then
- worklist="${worklist} ${gsv_x}"
- fi
- version_list="${worklist}"
- done
-
- verbose "Available versions: ${version_list}"
- }
-
- set_current_version()
- {
- if [ -f /boot/initrd.img-`uname -r` ]; then
- version=`uname -r`
- fi
- }
-
- set_linked_version()
- {
- linktarget=
- if [ -e /initrd.img ] && [ -L /initrd.img ]; then
- linktarget="$(basename "$(readlink /initrd.img)")"
- fi
-
- if [ -e /boot/initrd.img ] && [ -L /boot/initrd.img ]; then
- linktarget="$(basename "$(readlink /boot/initrd.img)")"
- fi
-
- if [ -z "${linktarget}" ]; then
- return
- fi
-
- version="${linktarget##initrd.img-}"
- }
-
- set_highest_version()
- {
- get_sorted_versions
- if [ -z "${version_list}" ]; then
- version=
- return
- fi
- set -- ${version_list}
- version=${1}
- }
-
- create()
- {
- if [ -z "${version}" ]; then
- usage "Create mode requires a version argument"
- fi
-
- set_initramfs
-
- if [ "${takeover}" = 0 ]; then
- if version_exists "${version}"; then
- panic "Cannot create version ${version}: already exists"
- fi
-
- if [ -e "${initramfs}" ]; then
- panic "${initramfs} already exists, cannot create."
- fi
- fi
-
- generate_initramfs
-
- run_bootloader
- }
-
- update()
- {
- if [ "${update_initramfs}" = "no" ]; then
- echo "update-initramfs: Not updating initramfs."
- exit 0
- fi
-
- if [ -z "${version}" ]; then
- set_highest_version
- fi
-
- if [ -z "${version}" ]; then
- set_linked_version
- fi
-
- if [ -z "${version}" ]; then
- set_current_version
- fi
-
- if [ -z "${version}" ]; then
- verbose "Nothing to do, exiting."
- exit 0
- fi
-
- set_initramfs
-
- ro_boot_check
-
- altered_check
-
- backup_initramfs
-
- generate_initramfs
-
- run_bootloader
-
- backup_booted_initramfs
- }
-
- delete()
- {
- if [ -z "${version}" ]; then
- usage "Delete mode requires a version argument"
- fi
-
- set_initramfs
-
- if [ "${takeover}" = 0 ]; then
- if [ ! -e "${initramfs}" ]; then
- panic "Cannot delete ${initramfs}, doesn't exist."
- fi
-
- if ! version_exists "${version}"; then
- panic "Cannot delete version ${version}: Not created by this utility."
- fi
- fi
-
- altered_check
-
- echo "update-initramfs: Deleting ${initramfs}"
-
- delete_sha1
-
- rm -f "${initramfs}" "${initramfs}.bak"
- }
-
- # Check for update mode on existing and modified initramfs
- altered_check()
- {
- # No check on takeover
- [ "${takeover}" = 1 ] && return 0
- if [ ! -e "${initramfs}" ]; then
- mild_panic "${initramfs} does not exist. Cannot update."
- fi
- if ! compare_sha1; then
- echo "update-initramfs: ${initramfs} has been altered." >&2
- mild_panic "update-initramfs: Cannot update. Override with -t option."
- fi
- }
-
- # Defaults
- verbose=0
- yes=0
- # We default to takeover=1 in Ubuntu, but not Debian
- takeover=0
-
- ##
-
- while getopts "k:cudyvtb:h?" flag; do
- case "${flag}" in
- k)
- version="${OPTARG}"
- ;;
- c)
- mode="c"
- ;;
- d)
- mode="d"
- ;;
- u)
- mode="u"
- ;;
- v)
- verbose="1"
- ;;
- y)
- yes="1"
- ;;
- t)
- takeover="1"
- ;;
- b)
- BOOTDIR="${OPTARG}"
- if [ ! -d "${BOOTDIR}" ]; then
- echo "Error: ${BOOTDIR} is not a directory." >&2
- exit 1
- fi
- ;;
- h|?)
- usage
- ;;
- esac
- done
-
- shift $((${OPTIND} - 1))
-
- if [ $# -ne 0 ]; then
- echo "Invalid argument for option -k." >&2
- usage
- fi
-
- # Validate arguments
- if [ -z "${mode}" ]; then
- usage "You must specify at least one of -c, -u, or -d."
- fi
-
- if [ "${version}" = "all" ] \
- || ( [ "${update_initramfs}" = "all" ] && [ -z "${version}" ] ); then
- : FIXME check for --yes, and if not ask are you sure
- get_sorted_versions
- if [ -z "${version_list}" ]; then
- verbose "Nothing to do, exiting."
- exit 0
- fi
-
- OPTS="-b ${BOOTDIR}"
- if [ "${verbose}" = "1" ]; then
- OPTS="${OPTS} -v"
- fi
- if [ "${takeover}" = "1" ]; then
- OPTS="${OPTS} -t"
- fi
- if [ "${yes}" = "1" ]; then
- OPTS="${OPTS} -y"
- fi
- for u_version in ${version_list}; do
- verbose "Execute: ${0} -${mode} -k \"${u_version}\" ${OPTS}"
- "${0}" -${mode} -k "${u_version}" ${OPTS}
- done
- exit 0
- fi
-
-
- case "${mode}" in
- c)
- create
- ;;
- d)
- delete
- ;;
- u)
- update
- ;;
- esac
-